package com.yj.spider.service;

import com.google.common.util.concurrent.AbstractExecutionThreadService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.Service;
import com.yj.spider.Manager.SpiderManager;
import com.yj.spider.Model.YjSpiderInfo;
import com.yj.spider.RegCenter.SpiderRegCenter;
import com.yj.spider.utils.IpUtils;
import lombok.extern.slf4j.Slf4j;
import org.nutz.dao.Dao;
import org.springframework.beans.factory.annotation.Autowired;
import us.codecraft.webmagic.Spider;

/**
 * 爬虫业务类
 */
@Slf4j
public  class YjSpider extends AbstractExecutionThreadService {

    private YjSpiderInfo yjSpiderInfo = new YjSpiderInfo();

    private SpiderRegCenter spiderRegCenter;
    private YjSpiderListener yjSpiderListener = new YjSpiderListener();
    private Spider spider = Spider.create(null);

    @Override
    protected void run() throws Exception {
        if (spider == null) {
            throw new RuntimeException("spider is null,please init spider before run spider!");
        }
        spider.start();
    }

    /**
     * 简单的YjSpiderBuilder
     * @return
     */
    public   YjSpider build(){
        SpiderManager.instance().addSpider(this);
        //spiderRegCenter =//
        return new YjSpider();
    }

    /**
     * 添加Spider监听器
     *
     * @return
     */
    public YjSpider setSPiderListener() {
        this.addListener(yjSpiderListener, MoreExecutors.directExecutor());
        return this;
    }

    @Override
    protected void shutDown() throws Exception {
        spider.stop();
        shutDown();
    }

    /**
     * 暴露WebMagic Spider信息
     *
     * @return
     */
    public Spider spider() {
        return spider;
    }


    public class YjSpiderListener extends Service.Listener {

        @Autowired
        Dao dao;

        /**
         * Called when the service transitions from {@linkplain Service.State#NEW NEW} to
         * {@linkplain Service.State#STARTING STARTING}. This occurs when {@link Service#startAsync} is called
         * the first time.
         */
        public void starting() {
            log.info("Spider Service {} starting ...", IpUtils.getIp());
            dao.insertOrUpdate(YjSpider.this);
        }

        /**
         * Called when the service transitions from {@linkplain Service.State#STARTING STARTING} to
         * {@linkplain Service.State#RUNNING RUNNING}. This occurs when a service has successfully started.
         */
        public void running() {
            log.info("Spider Service {} running ...", IpUtils.getIp());
            yjSpiderInfo.setService_status(State.RUNNING.ordinal());
            dao.insertOrUpdate(YjSpider.this);
        }

        /**
         * Called when the service transitions to the {@linkplain Service.State#STOPPING STOPPING} state. The
         * only valid values for {@code from} are {@linkplain Service.State#STARTING STARTING} or
         * {@linkplain Service.State#RUNNING RUNNING}. This occurs when {@link Service#stopAsync} is called.
         *
         * @param from The previous state that is being transitioned from.
         */
        public void stopping(Service.State from) {
            log.info("Spider Service {} stopping ...", IpUtils.getIp());
            yjSpiderInfo.setService_status(State.STOPPING.ordinal());
            dao.insertOrUpdate(YjSpider.this);
        }

        /**
         * Called when the service transitions to the {@linkplain Service.State#TERMINATED TERMINATED} state.
         * The {@linkplain Service.State#TERMINATED TERMINATED} state is a terminal state in the transition
         * diagram. Therefore, if this method is called, no other methods will be called on the
         * {@link Service.Listener}.
         *
         * @param from The previous state that is being transitioned from. The only valid values for
         *             this are {@linkplain Service.State#NEW NEW}, {@linkplain Service.State#RUNNING RUNNING} or
         *             {@linkplain Service.State#STOPPING STOPPING}.
         */
        public void terminated(Service.State from) {
            log.info("Spider Service {} terminated ...", IpUtils.getIp());
            yjSpiderInfo.setService_status(State.TERMINATED.ordinal());
            dao.insertOrUpdate(YjSpider.this);
        }

        /**
         * Called when the service transitions to the {@linkplain Service.State#FAILED FAILED} state. The
         * {@linkplain Service.State#FAILED FAILED} state is a terminal state in the transition diagram.
         * Therefore, if this method is called, no other methods will be called on the {@link Service.Listener}.
         *
         * @param from    The previous state that is being transitioned from. Failure can occur in any
         *                state with the exception of {@linkplain Service.State#NEW NEW} or {@linkplain Service.State#TERMINATED
         *                TERMINATED}.
         * @param failure The exception that caused the failure.
         */
        public void failed(Service.State from, Throwable failure) {
            log.error(failure.getMessage(), failure);
            yjSpiderInfo.setService_status(State.FAILED.ordinal());
            dao.insertOrUpdate(YjSpider.this);
        }

    }
}
